###############################################################################
#
# Copyright (C) 2007-TODAY Tiny ERP Pvt Ltd. All Rights Reserved.
#
# $Id$
#
# Developed by Tiny (http://openerp.com) and Axelor (http://axelor.com).
#
# The OpenERP web client is distributed under the "OpenERP Public License".
# It's based on Mozilla Public License Version (MPL) 1.1 with following
# restrictions:
#
# -   All names, links and logos of Tiny, Open ERP and Axelor must be
#     kept as in original distribution without any changes in all software
#     screens, especially in start-up page and the software header, even if
#     the application source code has been changed or updated or code has been
#     added.
#
# -   All distributions of the software must keep source code with OEPL.
#
# -   All integrations to any other software must keep source code with OEPL.
#
# If you need commercial licence to remove this kind of restriction please
# contact us.
#
# You can see the MPL licence at: http://www.mozilla.org/MPL/MPL-1.1.html
#
###############################################################################

"""
This modules implements custom authorization logic for the OpenERP Web Client.
"""

import time
import types
import re

import cherrypy
import pkg_resources

from openerp import rpc
from openerp import tools

from openerp.tools import expose
from openerp.tools import redirect


@expose(template="templates/login.mako")
def login(target, db=None, user=None, password=None, action=None, message=None, origArgs={}):

    url = rpc.session.connection_string
    url = str(url[:-1])

    dblist = []
    try:
        dblist = cherrypy.request.app.config['openerp-web'].get('selected_dbs') or rpc.session.listdb()
    except:
        message = _("Could not connect to server!")
        
    dbfilter = cherrypy.request.app.config['openerp-web'].get('dblist.filter')    
    if dbfilter:
        headers = cherrypy.request.headers
        host = headers.get('X-Forwarded-Host', headers.get('Host'))
        hcm = False
        if host.upper().find('HCM')>=0:
            hcm =True
            
        kdvn=False
        if host.upper().find('KINDEN')>=0:
            kdvn=True
        base = re.split('\.|:|/', host)[0]
        base_lst = []
        if base.upper()=='DEMO':
            base = 'stc'
        elif base.upper()=='OPENERP':
            base = 'for_testing'
        kd_prefix='NON_UNKOWN'
        if kdvn:
            kd_prefix='kdvn'
        
        if dbfilter == 'EXACT':
            if dblist is None:
                db = base
                dblist = [db]
                if len(base_lst):
                    dblist = base_lst
            else:
                dblist = [d for d in dblist if d.upper() == base.upper() or d.lower() in base_lst]

        elif dbfilter == 'UNDERSCORE':
            base = kd_prefix + '_'
            if dblist is None:
                if db and not db.startswith(base):
                    db = None
            else:
                dblist = [d for d in dblist if d.startswith(base)]

        elif dbfilter == 'BOTH':
            if dblist is None:
                if db and db != base and not db.startswith(kd_prefix + '_'):
                    db = None
            else:
                dblist = [d for d in dblist if ((d.upper().startswith(kd_prefix.upper() + '_') and hcm and d.upper().find('HCM')>=0) or (d.upper().startswith(kd_prefix.upper() + '_') and not hcm and not d.upper().find('HCM')>=0)) or d == base]
            
    info = None
    try:
        info = rpc.session.execute_noauth('common', 'login_message') or ''
    except:
        pass
    
    return dict(target=target, url=url, dblist=dblist, db=db, user=user, password=password,
            action=action, message=message, origArgs=origArgs, info=info)

def secured(fn):
    """A Decorator to make a SecuredController controller method secured.
    """
    def clear_login_fields(kw={}):

        if not kw.get('login_action'):
            return

        if kw.has_key('db'): del kw['db']
        if kw.has_key('user'): del kw['user']
        if kw.has_key('password'): del kw['password']
        if kw.has_key('login_action'): del kw['login_action']

    def get_orig_args(kw={}):
        if not kw.get('login_action'):
            return kw

        new_kw = kw.copy()

        if new_kw.has_key('db'): del new_kw['db']
        if new_kw.has_key('user'): del new_kw['user']
        if new_kw.has_key('password'): del new_kw['password']
        if new_kw.has_key('login_action'): del new_kw['login_action']

        return new_kw

    def wrapper(*args, **kw):
        """The wrapper function to secure exposed methods
        """

        if rpc.session.is_logged():
            # User is logged in; allow access
            #try:
            from openerp.controllers import check_user_online
            
        #    import cherrypy
            if check_user_online.is_check_user_online_module_installed(): #Update session_id and expiration_date when user is active
            
               cookie = cherrypy.response.cookie
                                   
               data = {'session_id' : cookie['session_id'].value, 'expiration_date' : str(check_user_online.get_date_obj(cookie['session_id']['expires']))}
            
               check_user_online.update_user_session(data)
            #except:
             #   pass
            
            from openerp import commands #If start openerp-web after shutdown set every user to not login
            if commands.get_test() and check_user_online.is_check_user_online_module_installed():                
                commands.set_test(False)
                rpc.RPCProxy('kdvn.sql.execute').execute("Update res_users set is_online=False,expiration_date=null,session_id=null")
            
            #Check when open view User Online View
            chk_ok = False 
            if args:
                tmp = args
                if '_terp_context' in tmp[0]:
                    if 'users_is_online' in tmp[0]['_terp_context']:                    
                        chk_ok = True
            elif kw:
                tmp = kw
                if '_terp_context' in tmp:
                    if 'users_is_online' in tmp['_terp_context']:                    
                        chk_ok = True
            if chk_ok:
                from openerp.controllers import check_user_online
                check_user_online.update_users_status()
            #End check User Online View
            
            clear_login_fields(kw)
            return fn(*args, **kw)
        else:
            # User isn't logged in yet.

            db = None
            user = None
            password = None
            message = None

            action = kw.get('login_action')

            # get some settings from cookies
            try:
                db = cherrypy.request.cookie['terp_db'].value
                user = cherrypy.request.cookie['terp_user'].value
            except:
                pass

            db = kw.get('db', db)
            user = kw.get('user', user)
            password = kw.get('password', password)

            # See if the user just tried to log in
            if rpc.session.login(db, user, password) <= 0:
                # Bad login attempt
                if action == 'login':
                    message = _("Bad username or password!")

                return login(cherrypy.request.path_info, message=message,
                        db=db, user=user, action=action, origArgs=get_orig_args(kw))

            # Authorized. Set db, user name in cookies
            expiration_time = time.strftime("%a, %d-%b-%Y %H:%M:%S GMT", time.gmtime(time.time() + ( 60 * 60 * 24 * 365 )))
            cherrypy.response.cookie['terp_db'] = db
            cherrypy.response.cookie['terp_user'] = user.encode('utf-8')
            cherrypy.response.cookie['terp_db']['expires'] = expiration_time;
            cherrypy.response.cookie['terp_user']['expires'] = expiration_time;

            # User is now logged in, so show the content
            clear_login_fields(kw)
            return fn(*args, **kw)

    return tools.decorated(wrapper, fn, secured=True)


def unsecured(fn):
    """A Decorator to make a SecuredController controller method unsecured.
    """
    def wrapper(*args, **kw):
        return fn(*args, **kw)

    return tools.decorated(wrapper, fn, secured=False)


class BaseController(object):
    pass


class SecuredController(BaseController):
    def __getattribute__( self, name ):
        value= object.__getattribute__(self, name)

        if isinstance(value, types.MethodType ) and hasattr(value, "exposed") and not (hasattr(value, "secured") and not value.secured):
            return secured(value)

        # Some other property
        return value

# vim: ts=4 sts=4 sw=4 si et

